#pragma once

template <typename MapTy>
auto Sort<MapTy>::update(SortDetail::MapIt<MapTy> it, bool ret) -> bool
{
	if (it == _data.end())
		return false;

	SortDetail::Item<MapTy>* pItem = dynamic_cast<SortDetail::Item<MapTy>*>(&it->second.get());
	if (!pItem)
		return false;

	size_t itemK = pItem->getSort();
	if (ret)
	{
		SortDetail::SubListIt<MapTy> subIt = pushSubBack(itemK, _list.end());
		if (subIt == _list.end())
			return false;

		SortDetail::Sub<MapTy>& sub = *subIt;
		sub._list.push_front(it);
		pItem->_subIt = subIt;
		pItem->_itemIt = sub._list.begin();
		return true;
	}

	switch ((pItem->_subIt->_id <=> itemK)._Value)
	{
	case std::strong_ordering::equal._Value:
		return true;
	case std::strong_ordering::less._Value:
		return moveItem2Sub(pItem, pushSubBack(itemK, pItem->_subIt));
	case std::strong_ordering::greater._Value:
		return moveItem2Sub(pItem, pushSubFront(itemK, pItem->_subIt));
	default:
		break;
	}

	return true;
}

template <typename MapTy>
auto Sort<MapTy>::pushSubBack(size_t itemK, SortDetail::SubListIt<MapTy> it) -> SortDetail::SubListIt<MapTy>
{
	if (it == _list.end())
		it = _list.begin();
	else
		it = std::next(it);

	for (; it != _list.end(); ++it)
	{
		switch ((it->_id <=> itemK)._Value)
		{
		case std::strong_ordering::equal._Value:
			return it;
		case std::strong_ordering::less._Value:
			break;
		case std::strong_ordering::greater._Value:
			{
				SortDetail::Sub<MapTy> sub;
				sub._id = itemK;
				sub._subIt = _list.insert(it, sub);
				return sub._subIt;
			}
			break;
		default:
			break;
		}
	}

	SortDetail::Sub<MapTy> sub;
	sub._id = itemK;
	sub._subIt = _list.insert(_list.end(), sub);
	return sub._subIt;
}

template <typename MapTy>
auto Sort<MapTy>::pushSubFront(size_t itemK, SortDetail::SubListIt<MapTy> it) -> SortDetail::SubListIt<MapTy>
{
	for (; it != _list.begin(); --it)
	{
		auto prevIt = std::prev(it);
		switch ((prevIt->_id <=> itemK)._Value)
		{
		case std::strong_ordering::equal._Value:
			return prevIt;
		case std::strong_ordering::less._Value:
			{
				SortDetail::Sub<MapTy> sub;
				sub._id = itemK;
				sub._subIt = _list.insert(it, sub);
				return sub._subIt;
			}
			break;
		case std::strong_ordering::greater._Value:
			break;
		default:
			break;
		}
	}

	SortDetail::Sub<MapTy> sub;
	sub._id = itemK;
	sub._subIt = _list.insert(_list.begin(), sub);
	return sub._subIt;
}

template <typename MapTy>
auto Sort<MapTy>::moveItem2Sub(SortDetail::Item<MapTy>* pItem, SortDetail::SubListIt<MapTy> it) -> bool
{
	if (it == _list.end())
		return false;

	SortDetail::Sub<MapTy>& newSub = *it;
	newSub._list.splice(newSub._list.begin(), pItem->_subIt->_list, pItem->_itemIt);
	if (pItem->_subIt->_list.empty())
		_list.erase(pItem->_subIt);

	pItem->_subIt = it;
	return true;
}

template <typename MapTy>
auto Sort<MapTy>::fillOs(std::ostream& os, bool (*check)(const SortDetail::Item<MapTy>&)) const -> std::ostream&
{
	bool first = true;
	for (auto it = _list.rbegin(); it != _list.rend(); ++it)
	{
		const SortDetail::Sub<MapTy>& sub = *it;
		for (auto subIt = sub._list.rbegin(); subIt != sub._list.rend(); ++subIt)
		{
			const auto& item = (*subIt)->second;
			if (!check(item))
				continue;

			if (first) first = false;
			else os << "; ";

			item.fillOs(os);
		}
	}

	return os;
}